﻿#ifndef __CDEV_H__
#define __CDEV_H__

#include "sys_types.h"
#include "psm-list.h"

typedef enum {
	DEV_IOCTL_SLEEP = 1001,
	DEV_IOCTL_WAKEUP = 1002,
} driver_ioctrl_t;

typedef long loff_t;

typedef struct file_operations {
	//////////////////////////////////////////////////////////////////////////////////////////////////
	// 读写，控制，打开，关闭的常规驱动接口。
	//////////////////////////////////////////////////////////////////////////////////////////////////
	ssize_t (*read) (handle_t, char *, size_t, loff_t *);
	ssize_t (*write) (handle_t, const char *, size_t, loff_t *);
	int (*ioctl) (handle_t, unsigned int, void *opt);
	int (*open) (handle_t, int, void *opt);
	int (*release) (handle_t);

	//////////////////////////////////////////////////////////////////////////////////////////////////
	// 该指针若不为空，则 dev_serive_task 会去轮询调用，若返回真（1）， 则会调用 fasync 去通知上层。
	// 返回上层后，上层需调用 read, write 接口去传输数据，但是需要驱动开发者实现自己的上下文数据。
	//////////////////////////////////////////////////////////////////////////////////////////////////
	int (*polling)(handle_t);

	//////////////////////////////////////////////////////////////////////////////////////////////////
	// 驱动的反应灵敏度，包括中断响应，主要看轮询的频率，单位是毫秒 ms.
	// 注意，所有驱动在一个 service 里运行，有个限制是所有驱动的轮询灵敏度必须是最小的那个的整数倍。
	//////////////////////////////////////////////////////////////////////////////////////////////////
	int heart_throb;

	//////////////////////////////////////////////////////////////////////////////////////////////////
	// 这个接口由 dev_serive_task 发起调用，通知上层。
	// 中断类驱动没有 polling 接口，可在实例实现里面直接调用 dev_IRQNotify 激发回调 fasync
	//////////////////////////////////////////////////////////////////////////////////////////////////
	int (*fasync) (handle_t, unsigned long *);
}file_operations_t;

//////////////////////////////////////////////////////////////////////////////////////////////////
// 驱动设备表述表，主要是描述一个驱动的基本信息。
// 注意 Create 接口实现 0 全局变量的约束，可以实现驱动实现的多实例化构建。
//////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct{
	file_operations_t* (*Create)(uint32_t major_minor);
	uint16_t major;
	uint16_t minor;
	const char *name;
}dev_description_t;

//////////////////////////////////////////////////////////////////////////////////////////////////
// 注册和反注册只需要传入驱动设备描述表，该表可以实现扩展而无需修改注册函数参数，易于维护。
//////////////////////////////////////////////////////////////////////////////////////////////////
int register_chrdev(const dev_description_t *desp);
void unregister_chrdev(const dev_description_t *desp);

//////////////////////////////////////////////////////////////////////////////////////////////////
// 这个是驱动开发者的驱动属性如果是中断类型，在中断回调函数中通过该接口通知 _dev_service_task_ 对外进行回调。
//////////////////////////////////////////////////////////////////////////////////////////////////
void dev_IRQNotify(handle_t handle, unsigned long payload);

//////////////////////////////////////////////////////////////////////////////////////////////////
// 下面接口需被驱动开发者实现，由驱动框架来调用，而上层是通过驱动开发者提供的接口间接调用的。
//////////////////////////////////////////////////////////////////////////////////////////////////
handle_t dev_Open(const char *pathname, int flags, ...);
int dev_Close(handle_t* handle);
ssize_t dev_Read(handle_t handle, void *buf, size_t count, loff_t *loff);
ssize_t dev_Write(handle_t handle, const void *buf, size_t count, loff_t *loff);
int dev_Ioctl(handle_t handle, unsigned long request, ...);

//////////////////////////////////////////////////////////////////////////////////////////////////
// 对所有已注册驱动进行统一的 ioctl 调度，目前规定了 sleep，wakeup 统一的方法
//////////////////////////////////////////////////////////////////////////////////////////////////
int devs_Ioctl(unsigned long request, ...);

#endif

